home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Mac-Source 1994 July
/
Mac-Source_July_1994.iso
/
C and C++
/
Compilers⁄Interps
/
kevoSource
/
portBrowser.c
< prev
next >
Wrap
Text File
|
1993-05-12
|
37KB
|
1,401 lines
/* Kevo -- a prototype-based object-oriented language */
/* (c) Antero Taivalsaari 1991-1993 */
/* Some parts (c) Antero Taivalsaari 1986-1988 */
/* portBrowser.c: Non-portable object browser */
#include "global.h"
#include "portGlobal.h"
/*---------------------------------------------------------------------------*/
/* Graphical user interface (GUI) initialization */
/* Open and initialize the browser */
void openBrowser(target, windowIdent, browserKind)
OBJECT* target; /* The object to be browsed */
char* windowIdent; /* The (partial) name of the window */
int browserKind; /* Browser kind (either BrowserWKind or CloneBrWKind) */
{
WindowPtr browserWindow;
WindowPtr frontWindow;
GrafPtr savePort;
WINFO* thisWinfo;
ListHandle iconList;
int wKind;
int columns; /* Initial number of columns in the browser */
int viewWhat; /* Initial view mode (ALL, BEHAVIOR, DATA) */
/* Check if we can find an existing browser for the requested object */
browserWindow = findBrowser(target);
/* If we can, then select the existing browser */
if (browserWindow) {
/* If the window is hidden, make it visible */
if (!((WindowPeek)browserWindow)->visible) ShowWindow(browserWindow);
SelectWindow(browserWindow);
return;
}
/* Otherwise, open a new browser window for the requested object */
/* First, check if the currently selected window is a browser window */
frontWindow = FrontWindow();
wKind = getWindowKind(frontWindow);
/* If the front window is a browser window, then we'll
duplicate the view mode information from that window.
*/
if (wKind == BrowserWKind || wKind == CloneBrWKind) {
iconList = getBrowserIcons(frontWindow);
/* If we are opening a clone family, always display both data and behavior */
if (browserKind == CloneBrWKind)
viewWhat = ALL;
else viewWhat = getViewMode(iconList);
columns = ((*iconList)->dataBounds).right;
}
/* Otherwise, use the default view mode settings */
/* (defaults: view both data and behavior, one column display) */
else {
viewWhat = ALL;
columns = 1;
}
/* Build a new window */
browserWindow = buildWindow("\p");
ShowWindow(browserWindow);
GetPort(&savePort);
SetPort(browserWindow);
TextFont(newYork);
TextFace(0);
TextSize(10);
SetPort(savePort);
/* Change the window kind to the requested kind */
thisWinfo = (WINFO*)GetWRefCon(browserWindow);
thisWinfo->wKind = browserKind;
/* Store the window identifier to the appropriate field */
setBrowserIdent(browserWindow, windowIdent);
/*
If there are no previous browser windows open,
create a new task called 'browserTask', and set
it to execute the shell in the root context.
This task will allow many commands given from the browser
to be executed on background, thus making the browser snappier.
*/
if (browserCount == 0) {
TASK** tempUp = up;
browserTask = buildTask();
setTaskBehavior(browserTask, oShell);
setTaskCWD(browserTask, oUserRoot);
/* Browser task does not normally refer to any window */
(*browserTask)->window = NIL;
/* Instead, its output goes to '/dev/null' :-) */
/* and error messages to the console */
up = browserTask;
errfile = confile;
up = tempUp;
/* Browser task also has its own error handler */
/* to avoid deadlocks as a result of errors within */
/* critical regions (which are used for method redefinitions) */
textToKeyBuffer(browserTask, "' brError MY error !");
crsToKeyBuffer(browserTask);
activateTask(browserTask);
}
/* Browser window refers to an icon list via its WINFO structure */
iconList = buildIconList(browserWindow, target, LastBrowser, columns, viewWhat);
setBrowserIcons(browserWindow, iconList);
LActivate(TRUE, iconList);
LastBrowser = browserWindow;
browserCount++;
SelectWindow(browserWindow);
}
/* Reuse a previous browser window by making it display another object */
void reuseBrowser(target, windowIdent, oldBrowser, newKind)
OBJECT* target; /* The object to be browsed */
char* windowIdent; /* The (partial) window name */
WindowPtr oldBrowser; /* An existing browser window */
int newKind; /* The new browser kind (BrowserWKind, CloneBrWKind) */
{
WindowPtr existingBrowser;
WINFO* thisWinfo;
/* Check if we can find an existing browser for the requested object */
existingBrowser = findBrowser(target);
/* If we can, then select the existing browser */
/* And delete the old one */
if (existingBrowser) {
deleteBrowser(oldBrowser);
SelectWindow(existingBrowser);
return;
}
/* Change the browser task context to the requested object */
setBrowserTarget(oldBrowser, target);
/* Change the window kind to the requested kind */
thisWinfo = (WINFO*)GetWRefCon(oldBrowser);
thisWinfo->wKind = newKind;
/* Store the window identifier to the appropriate field */
setBrowserIdent(oldBrowser, windowIdent);
/* Update the browser view using the new target */
/* and old parameters from the LINFO structure */
updateBrowser(oldBrowser);
}
/* Finalize and delete a given browser */
void deleteBrowser(browserWindow)
WindowPtr browserWindow;
{
ListHandle iconList = getBrowserIcons(browserWindow);
if (browserCount > 1 || (browserCount == 1 && killTask(browserTask))) {
unlinkBrowser(browserWindow);
deleteIconList(iconList);
deleteWinfo(browserWindow);
DisposeWindow(browserWindow);
if (--browserCount == 0) browserTask = NIL;
}
else fprintf(confile, "== Cannot delete the only active task in the system ==\n");
}
/* Unlink the given browser from the browser list */
void unlinkBrowser(browserWindow)
WindowPtr browserWindow;
{
WindowPtr prevBr = NIL;
WindowPtr thisBr = LastBrowser;
while (thisBr) {
if (browserWindow == thisBr) {
if (!prevBr) LastBrowser = getPrevBrowser(thisBr);
else setPrevBrowser(prevBr, getPrevBrowser(thisBr));
return;
}
prevBr = thisBr;
thisBr = getPrevBrowser(thisBr);
}
}
/* Given an object, find the possible corresponding browser from the browser list */
WindowPtr findBrowser(target)
OBJECT* target;
{
WindowPtr thisBr = LastBrowser;
while (thisBr) {
if (getBrowserTarget(thisBr) == target) return(thisBr);
thisBr = getPrevBrowser(thisBr);
}
return(NIL);
}
/* Update the view of the given browser */
void refreshBrowser(browserWindow)
WindowPtr browserWindow;
{
ListHandle iconList = getBrowserIcons(browserWindow);
OBJECT* cwd = getBrowserTarget(browserWindow);
CONTEXT* thisContext = getContext(cwd);
PAIR* thisPair = thisContext->firstPair;
int viewMode = getViewMode(iconList);
Cell cell;
short len;
OBJECT* object;
PAIR* valuePair;
int stillMore;
int count;
/*
If we are displaying a clone family, we should remove the possible extra
slots from the end of the object by optimizing the list
*/
if (getWindowKind(browserWindow) == CloneBrWKind) optimizeList((LIST*)cwd);
/* Resize the Mac Icon List by counting the number of cells in the object */
resizeIconList(iconList, cwd);
/* Display each property in the object in the Icon List */
cell.h = 0; cell.v = 0;
while (thisPair = getNextMaskedPair(thisPair, viewMode)) {
int pairKind = recognizeObject(thisPair->ofa);
int hidden = thisPair->ffa & HiddenFlag;
switch (pairKind) {
case PRIMITIVE:
len = sprintf(charbuffer, "%s %s", asString(pairKind, hidden), thisPair->nfa);
break;
case REF:
case VAR:
case CONST:
{
switch (pairKind) {
case REF: object = *getREFslot(thisPair); break;
case VAR: object = *getVARslot(cwd, thisPair); break;
case CONST: object = *getREFslot(thisPair); break;
}
if (isContextObject(object)) {
if (valuePair = findTypeForward(object))
len = sprintf(charbuffer, "%s %s (%s)", asString(pairKind, hidden),
thisPair->nfa, valuePair->nfa);
else len = sprintf(charbuffer, "%s %s (<no type>:%d)", asString(pairKind, hidden),
thisPair->nfa, object);
}
else len = sprintf(charbuffer, "%s %s (%d)", asString(pairKind, hidden),
thisPair->nfa, object);
break;
}
case METHOD:
len = sprintf(charbuffer, "%s %s", asString(pairKind, hidden), thisPair->nfa);
break;
}
LSetCell(charbuffer, len, cell, iconList);
stillMore = LNextCell(TRUE, TRUE, &cell, iconList);
thisPair = thisPair->sfa;
}
if (viewMode != BEHAVIOR) {
/* Add the possible anonymous array slots to the end of the icon list */
count = AnonymousSlots;
while (count) {
object = (OBJECT*)*((int*)cwd->mfa + cwd->sfa - count);
if (isContextObject(object)) {
if (valuePair = findTypeForward(object))
len = sprintf(charbuffer, "<%d> (%s:%d) ", cwd->sfa-count-1, valuePair->nfa, object);
else len = sprintf(charbuffer, "<%d> (<no type>:%d) ", cwd->sfa-count-1, object);
}
else len = sprintf(charbuffer, "<%d> (%d) ", cwd->sfa-count-1, object);
LSetCell(charbuffer, len, cell, iconList);
stillMore = LNextCell(TRUE, TRUE, &cell, iconList);
count--;
}
}
/* Empty the rest of the cells in the Icon List */
if (stillMore) {
/* Old implementation:
// LClrCell(cell, iconList);
// while (LNextCell(TRUE, TRUE, &cell, iconList)) LClrCell(cell, iconList);
*/
LSetCell(" ", 3, cell, iconList);
while (LNextCell(TRUE, TRUE, &cell, iconList))
LSetCell(" ", 3, cell, iconList);
}
}
/* Update the title and view of the given browser */
void updateBrowser(browserWindow)
WindowPtr browserWindow;
{
OBJECT* cwd = getBrowserTarget(browserWindow);
CONTEXT* context = getContext(cwd);
/* Update the title of the window with the current type information */
/* This operation is rather time consuming */
updateBrowserTitle(browserWindow);
/* Refresh the contents of the browser */
refreshBrowser(browserWindow);
/*
For security, perform some integrity checks for the object.
This allows the user to notice possible memory leak problems etc.
in his programs earlier before they cause some totally obscure errors.
Problems will be reported to console along with a three beeps.
However, since rootContext is so big (= time-consuming to check),
we never perform the integrity checks for that object.
*/
/* if (context != rootContext) checkIntegrity(context); */
}
/* Update the browser title, using current type information */
void updateBrowserTitle(browserWindow)
WindowPtr browserWindow;
{
OBJECT* cwd = getBrowserTarget(browserWindow);
int wKind = getWindowKind(browserWindow);
/* Special case: the Root object */
if (cwd == oUserRoot) {
SetWTitle(browserWindow, "\pRoot");
return;
}
switch (wKind) {
case BrowserWKind: {
char* thisName = getBrowserIdent(browserWindow);
decodeObjectType(thisName, cwd);
break;
}
case CloneBrWKind: {
OBJECT* object = (OBJECT*)fetchFromList((LIST*)cwd, 1);
if (object == oUserRoot) sprintf(charbuffer, "Root clone family");
else {
PAIR* thisPair = findTypeForward(object);
if (thisPair)
sprintf(charbuffer, "%s clone family", thisPair->nfa);
else sprintf(charbuffer, "<anon> clone family");
}
CtoPstr(charbuffer);
break;
}
}
SetWTitle(browserWindow, charbuffer);
}
/* Change the number of columns in the browser */
void recolumnBrowser(browserWindow, newCols)
WindowPtr browserWindow;
int newCols;
{
ListHandle iconList = getBrowserIcons(browserWindow);
OBJECT* cwd = getBrowserTarget(browserWindow);
WindowPtr oldPrevBr = getPrevBrowser(browserWindow);
int oldCols = ((*iconList)->dataBounds).right;
int oldViewMode = getViewMode(iconList);
if (newCols == oldCols) return;
EraseRect(&browserWindow->portRect);
deleteIconList(iconList);
iconList = buildIconList(browserWindow, cwd, oldPrevBr, newCols, oldViewMode);
setBrowserIcons(browserWindow, iconList);
LActivate(TRUE, iconList);
updateBrowser(browserWindow);
DrawGrowIcon(browserWindow);
}
/* React to a double click */
void handleDoubleClick(browserWindow, optKey)
WindowPtr browserWindow;
int optKey;
{
ListHandle iconList = getBrowserIcons(browserWindow);
OBJECT* cwd = getBrowserTarget(browserWindow);
CONTEXT* context = getContext(cwd);
Cell cell = LLastClick(iconList);
int index = cellToIndex(iconList, cell);
int viewMode = getViewMode(iconList);
PAIR* thisPair = indexedFind(context, index, viewMode);
int pairKind;
OBJECT* object;
/* If the object contains a pair for the selected cell */
if (thisPair) {
switch (pairKind = recognizeObject(thisPair->ofa)) {
case PRIMITIVE:
if (optKey) {
/* If option key is pressed during double click, execute the primitive */
numberToKeyBuffer(browserTask, (int)cwd);
textToKeyBuffer(browserTask, " CD");
crsToKeyBuffer(browserTask);
numberToKeyBuffer(browserTask, thisPair->ofa);
textToKeyBuffer(browserTask, " execute");
crsToKeyBuffer(browserTask);
}
else SysBeep(1);
break;
case REF:
case VAR:
case CONST:
{
switch (pairKind) {
case REF: object = *getREFslot(thisPair); break;
case VAR: object = *getVARslot(cwd, thisPair); break;
case CONST: object = *getREFslot(thisPair); break;
}
if (isContextObject(object)) {
if (optKey) reuseBrowser(object, thisPair->nfa, browserWindow, BrowserWKind);
else openBrowser(object, thisPair->nfa, BrowserWKind);
}
else SysBeep(1);
break;
}
case METHOD: {
if (optKey) {
/* If option key is pressed during double click, execute the method */
numberToKeyBuffer(browserTask, (int)cwd);
textToKeyBuffer(browserTask, " CD");
crsToKeyBuffer(browserTask);
numberToKeyBuffer(browserTask, thisPair->ofa);
textToKeyBuffer(browserTask, " execute");
crsToKeyBuffer(browserTask);
}
else {
WindowPtr methodWindow;
TASK** tempUp = up;
PAIR* typePair;
yieldTo(browserTask);
pushContext((int*)cwd);
if (typePair = findTypeForward(cwd))
sprintf(charbuffer, "%s METHOD %s", typePair->nfa, thisPair->nfa);
else sprintf(charbuffer, "METHOD %s", thisPair->nfa);
CtoPstr(charbuffer);
/* Set the output of browser task temporarily to a window */
methodWindow = buildTEWindow(charbuffer);
(*browserTask)->window = (int*)methodWindow;
ShowWindow(methodWindow);
outfile = (FILE*)0;
setMethodContext(methodWindow, cwd);
setMethodPair(methodWindow, thisPair);
SelectWindow(methodWindow);
decompile(thisPair->ofa);
/* Set the output of browser task back to console */
(*browserTask)->window = NIL;
/* outfile = confile; */
errfile = confile;
theTask = NIL;
theText = NIL;
(void)popContext();
yieldTo(tempUp);
}
break;
}
}
}
else if (AnonymousSlots) {
/* No matching pair -> handle the possible anonymous slot access */
int position = index - MaskedPairs;
object = (OBJECT*)*((int*)cwd->mfa + position + 1);
if (isContextObject(object)) {
if (optKey) reuseBrowser(object, NIL, browserWindow, BrowserWKind);
else openBrowser(object, NIL, BrowserWKind);
}
else SysBeep(1);
}
}
/*
Open browsers for all the parent or child clone families
on the basis of the currently selected browser window.
*/
void browseCloneFamilies(browserWindow, familyStr)
WindowPtr browserWindow;
char* familyStr; /* parameter string should be either "parent" or "child" */
{
OBJECT* cwd;
LIST* cwdFamily;
int index;
/*
This operation can be invoked from both "normal" browser windows
and from clone family windows. We must initialize the variables
differently depending on this.
*/
switch (getWindowKind(browserWindow)) {
case BrowserWKind:
cwd = getBrowserTarget(browserWindow);
if (strcmp(familyStr, "parent") == 0)
cwdFamily = getContext(cwd)->parentFamilies;
else cwdFamily = getContext(cwd)->childFamilies;
break;
case CloneBrWKind:
/* Note: this assumes that the clone family has at least one member */
cwd = fetchFromList((LIST*)getBrowserTarget(browserWindow), 1);
if (strcmp(familyStr, "parent") == 0)
cwdFamily = getContext(cwd)->parentFamilies;
else cwdFamily = getContext(cwd)->childFamilies;
break;
}
/* If the family list is empty -> do nothing */
if (cwdFamily->logicalSize == 0) return;
/* Otherwise, open a clone family browser for each of the members */
for (index = 1; index <= cwdFamily->logicalSize; index++) {
LIST* thisFamily = (LIST*)fetchFromList(cwdFamily, index);
if (!isContextObject((OBJECT*)thisFamily)) {
fprintf(confile, "== Integrity error detected: %s family is not a valid object ==\n", familyStr);
reportIntegrityError();
ownLongJmp();
}
/* The window will be opened only if the family contains members */
/* (if the system works correctly, all the families do contain members) */
if (thisFamily->logicalSize > 0) {
/*
Since we may have to open multiple windows,
set the browser task to open the browser on background
so as to allow multitasking to operate without delays.
*/
/* Remember that 'numberToKeyBuffer' changes 'charbuffer' */
numberToKeyBuffer(browserTask, (int)thisFamily);
textToKeyBuffer(browserTask, " cfBrowse");
crsToKeyBuffer(browserTask);
}
else {
fprintf(confile, "== Integrity error detected: empty %s family ==\n", familyStr);
reportIntegrityError();
ownLongJmp();
}
}
}
/* Assign the given object to the selected slot in the target window */
/*
The object will be assigned only if there is exactly one slot selected
in the icon list, and that slot is either a shared variable (REF) or
an instance variable (VAR)
Actually, the same checks are performed in 'doBrowserDisable', but they
are kept here for safety.
*/
void assignObject(browserWindow, source)
WindowPtr browserWindow; /* The target window */
OBJECT* source; /* The object to be assigned */
{
OBJECT* cwd = getBrowserTarget(browserWindow);
ListHandle iconList = getBrowserIcons(browserWindow);
int selected = countSelectedCells(iconList);
if (selected != 1) {
SysBeep(1);
fprintf(confile, "== Exactly one variable slot must be active during assignment ==\n");
return;
}
else {
PAIR* thisPair;
OBJECT* target;
OBJECT** slot;
int pairKind;
Cell cell;
cell.h = -1; cell.v = 0;
(void)nextSelectedCell(iconList, &cell);
thisPair = cellToPair(browserWindow, cell);
if (!thisPair) {
SysBeep(1);
fprintf(confile, "== The target slot in assignment must be either a VAR or a REF ==\n");
return;
}
target = thisPair->ofa;
pairKind = recognizeObject(target);
switch (pairKind) {
case REF:
case VAR:
switch (pairKind) {
case REF: slot = getREFslot(thisPair); break;
case VAR: slot = getVARslot(cwd, thisPair); break;
}
*slot = source;
updateBrowser(browserWindow);
/* Select the second topmost window so as to confirm */
/* which object has been assigned */
openBrowser(source, thisPair->nfa, BrowserWKind);
break;
default:
SysBeep(1);
fprintf(confile, "== The target slot in assignment must be either a VAR or a REF ==\n");
break;
}
}
}
/* Open command shell (value editor) window for the given object */
void openShellForThis(object)
OBJECT* object;
{
TASK** newTask = buildTask();
WindowPtr newWindow;
PAIR* typePair;
/* In the browser mode, we copy the initial
context from the current browser task.
The execution will be started from 'shell' rather than 'boot'.
*/
setTaskBehavior(newTask, oShell);
setTaskCWD(newTask, object);
typePair = findTypeForward(object);
if (typePair)
sprintf(charbuffer, "Command Shell (%s:%d)", typePair->nfa, object);
else sprintf(charbuffer, "Command Shell (object %d)", object);
CtoPstr(charbuffer);
/* Build a new TextEdit window for the newly created task */
newWindow = buildTEWindow(charbuffer);
if (newWindow) {
(*newTask)->window = (int*)newWindow;
ShowWindow(newWindow);
SelectWindow(newWindow);
}
activateTask(newTask);
}
/* ------------------------------------------------------------------------ */
/* Icon List operations */
/* Build an icon list structure, using the Mac Toolbox List Manager Package */
/* Note that these lists have nothing to do with the lists defined in 'lists.h' */
ListHandle buildIconList(thisWindow, target, prevBrowser, columnNumber, viewWhat)
WindowPtr thisWindow;
OBJECT* target;
WindowPtr prevBrowser;
int columnNumber;
int viewWhat;
{
ListHandle iconList;
Point cSize;
Rect viewRect, boundsRect;
/* Set the cell dimensions (horizontal and vertical) */
/* Defaults are h: 480 / cols and v: 18 */
cSize.h = ICONLINELENGTH / columnNumber;
cSize.v = ICONCELLHEIGHT;
boundsRect.left = 0;
boundsRect.top = 0;
boundsRect.right = columnNumber;
boundsRect.bottom = 1;
BlockMove(&thisWindow->portRect, &viewRect, sizeof(Rect));
viewRect.right -= 15; /* Must be 15 */
viewRect.bottom -= 15; /* Must be 15 */
/* Build a new Mac Toolbox List */
iconList = LNew(&viewRect, /* Screen size of the icon list */
&boundsRect, /* Number of rows and columns */
cSize, /* Cell size */
333, /* List definition (LDEF) resource id, default=0/custom=333 */
thisWindow, /* The window in which the icon list resides */
TRUE, /* drawIt (cell drawing is enabled) */
TRUE, /* hasGrow (there is a size box) */
TRUE, /* scrollHoriz (there is a horizontal scroll bar) */
TRUE); /* scrollVert (there is a vertical scroll bar) */
/* Empty cells should not be highlighted */
(*iconList)->selFlags |= lNoNilHilite;
/* Create the icon list information structure */
(*iconList)->refCon = (long)createLinfo(viewWhat, target, prevBrowser);
return(iconList);
}
/* Delete an icon list structure */
void deleteIconList(iconList)
ListHandle iconList;
{
LINFO* thisLinfo = (LINFO*)(*iconList)->refCon;
/* Delete the associated information structure */
deleteLinfo(thisLinfo);
/* Delete the Mac Toolbox List itself */
LDispose(iconList);
}
/* Add or remove columns from the icon list if needed */
void resizeIconList(iconList, cwd)
ListHandle iconList;
OBJECT* cwd;
{
CONTEXT* context = getContext(cwd);
int viewMode = getViewMode(iconList);
int cols = ((*iconList)->dataBounds).right;
int lastRow;
int delta; /* Change in row count */
Cell cell;
/* Set the values of the global icon list item counts */
/* Number of appropriate pairs in the current object */
/* This is a global variable */
MaskedPairs = maskedCountPairs(context, viewMode);
/* Number of anynymous (array) slots in the current object */
/* This is a global variable */
AnonymousSlots = countArraySlots(cwd);
/* In behavior display mode, we don't display the anonymous array slots */
/* so they will not be added to the cell count when resizing the icon list */
/* CellsInTotal is also a global variable that tells how many cells/icons the */
/* current browser has */
if (viewMode != BEHAVIOR)
CellsInTotal = MaskedPairs + AnonymousSlots;
else CellsInTotal = MaskedPairs;
lastRow = (CellsInTotal+cols-1) / cols;
delta = lastRow - ((*iconList)->dataBounds).bottom;
if (delta > 0) { /* Lines must be added */
/* second argument must be bigger than biggest possible column number */
LAddRow(delta, -1, iconList);
return;
}
if (delta < 0) { /* Lines must be deleted */
LDelRow(-delta, 0, iconList);
}
}
/* Determine the correct size for the browser */
/* This routine is used for zoom box operation */
void determineBrowserWindowSize(browserWindow)
WindowPtr browserWindow;
{
ListHandle iconList = getBrowserIcons(browserWindow);
int columns = ((*iconList)->dataBounds).right;
WStateData** wDataHdl;
Rect newRect;
int offsetLeft = 0 - browserWindow->portBits.bounds.left;
int offsetTop = 0 - browserWindow->portBits.bounds.top;
int width;
int height;
if (columns == 1) {
width = ICONLINELENGTH / 2 + SCROLLBARWIDTH;
height = CellsInTotal*ICONCELLHEIGHT + SCROLLBARWIDTH + 6;
}
else {
width = ICONLINELENGTH + SCROLLBARWIDTH;
height = (((CellsInTotal+columns-1) / 4) * ICONCELLHEIGHT) + SCROLLBARWIDTH + 6;
}
/* Ensure that window doesn't become too large for the screen */
if (height > screenBits.bounds.bottom - (SCROLLBARWIDTH*2 + 15))
height = screenBits.bounds.bottom - (SCROLLBARWIDTH*2 + 15);
/* Ensure that window doesn't become too small either */
else if (height < ICONCELLHEIGHT*3 + SCROLLBARWIDTH)
height = ICONCELLHEIGHT*3 + SCROLLBARWIDTH;
/* Set the calculated browser size for zoom box usage */
SetRect(&newRect, offsetLeft, offsetTop, offsetLeft + width, offsetTop + height);
wDataHdl = (WStateData**)((WindowPeek)browserWindow)->dataHandle;
BlockMove(&newRect, &(*wDataHdl)->stdState, sizeof(Rect));
}
/* Return true if there is yet another selected cell in the icon list */
/* The selected cell is returned in parameter 'nextCell' */
int nextSelectedCell(iconList, nextCell)
ListHandle iconList;
Cell* nextCell;
{
int cols = (*iconList)->dataBounds.right;
int rows = (*iconList)->dataBounds.bottom;
int selected = FALSE;
while (nextCell->v < rows) {
nextCell->h++;
if (nextCell->h >= cols) {
nextCell->h = 0;
nextCell->v++;
}
if (selected = LGetSelect(FALSE, nextCell, iconList)) break;
}
return(selected);
}
/* Return true if there is yet another selected cell in the icon list */
/* The selected cell is returned in parameter 'prevCell' */
int prevSelectedCell(iconList, prevCell)
ListHandle iconList;
Cell* prevCell;
{
int cols = (*iconList)->dataBounds.right;
int selected = FALSE;
while (prevCell->v >= 0) {
prevCell->h--;
if (prevCell->h < 0) {
prevCell->h = cols-1;
prevCell->v--;
}
if (selected = LGetSelect(FALSE, prevCell, iconList)) break;
}
return(selected);
}
/* Return the number of selected cells in the icon list */
int countSelectedCells(iconList)
ListHandle iconList;
{
Cell cell;
int count = 0;
cell.h = -1; cell.v = 0;
while (nextSelectedCell(iconList, &cell)) count++;
return(count);
}
/* Add a new cell (pair) to the object being browsed */
void addNewCell(browserWindow, slotType, name)
WindowPtr browserWindow;
int slotType;
char* name;
{
OBJECT* cwd = getBrowserTarget(browserWindow);
CONTEXT* context;
PAIR* newPair;
OBJECT* object;
/* The current version does not support addition of cells to descendants */
if (whoToModify == DERIVATIVES) {
SysBeep(1);
fprintf(confile, "== This version does not support addition of slots in the 'derivatives' ==\n");
fprintf(confile, "== mode (use 'clone family' mode and CUT/COPY/PASTE instead) ==\n");
return;
}
/* Create a new clone family if needed */
if (whoToModify == THIS_ONLY) deriveObject(cwd);
/* Add the appropriate slot */
switch (slotType) {
case REF:
object = createClosure(2);
object->mfa->efa = (int*)oREF;
break;
case REF+8:
pBuildDir();
object = createClosure(2);
object->mfa->efa = (int*)oREF;
object->mfa->pfa = (int*)popData();
break;
case VAR:
object = createClosure(2);
object->mfa->efa = (int*)oVAR;
object->mfa->pfa = (int*)cwd->sfa;
resizeFamilyMembers(cwd, cwd->sfa+1);
break;
case CONST:
object = createClosure(2);
object->mfa->efa = (int*)oSharedConst;
break;
case METHOD:
object = createClosure(1);
break;
}
context = getContext(cwd);
newPair = addPair(context, name, object);
/* Possibly change the object's clone family */
confirmObjectType(cwd, whoToModify, ADDING_SOMETHING);
updateBrowser(browserWindow);
}
/* Remove a given cell (pair) from the object being browsed */
void removeCell(browserWindow, cell)
WindowPtr browserWindow;
Cell cell;
{
PAIR* thisPair = cellToPair(browserWindow, cell);
if (!thisPair) return;
unlinkPair(thisPair);
free(thisPair);
}
/* Change encapsulation of a given cell (pair) */
void hideShowCell(browserWindow, cell)
WindowPtr browserWindow;
Cell cell;
{
PAIR* thisPair = cellToPair(browserWindow, cell);
if (!thisPair) return;
if (thisPair->ffa & HiddenFlag)
/* reset the hidden flag */
thisPair->ffa &= ~HiddenFlag;
else
/* raise the hidden flag */
thisPair->ffa |= HiddenFlag;
}
/* Add a character to the property name in a cell */
void addToCell(iconList, cell, c)
ListHandle iconList;
Cell cell;
char c;
{
char qualifier[16];
char name[128];
short count = CHARBUFLEN;
int index = cellToIndex(iconList, cell);
if (index > MaskedPairs) { SysBeep(1); return; }
LGetCell(charbuffer, &count, cell, iconList);
charbuffer[count] = 0;
/* We have to initialize name, because charbuffer may not contain two words */
name[0] = 0;
sscanf(charbuffer, "%s %s", qualifier, name);
name[strlen(name)+1] = 0;
name[strlen(name)] = c;
sprintf(charbuffer, "%s %s", qualifier, name);
LSetCell(charbuffer, (short)(strlen(qualifier)+strlen(name)+1), cell, iconList);
}
/* Remove a character from the property name in a cell */
void removeFromCell(iconList, cell)
ListHandle iconList;
Cell cell;
{
char qualifier[16];
char name[128];
short count = CHARBUFLEN;
int index = cellToIndex(iconList, cell);
if (index > MaskedPairs) { SysBeep(1); return; }
LGetCell(charbuffer, &count, cell, iconList);
charbuffer[count] = 0;
name[0] = 0;
sscanf(charbuffer, "%s %s", qualifier, name);
if (strlen(name)) {
name[strlen(name)-1] = 0;
sprintf(charbuffer, "%s %s", qualifier, name);
LSetCell(charbuffer, (short)(strlen(qualifier)+strlen(name)+1), cell, iconList);
}
else SysBeep(1);
}
/* Rename the property in a cell using the possibly changed name */
void renameCell(browserWindow, cell)
WindowPtr browserWindow;
Cell cell;
{
OBJECT* cwd = getBrowserTarget(browserWindow);
ListHandle iconList = getBrowserIcons(browserWindow);
PAIR* thisPair;
char qualifier[16];
char name[128];
short count = CHARBUFLEN;
/* The current version does not support renaming of cells to descendants */
if (whoToModify == DERIVATIVES) {
SysBeep(1);
fprintf(confile, "== This version does not support renaming of slots in the 'derivatives' ==\n");
fprintf(confile, "== mode (use 'clone family' mode and CUT/COPY/PASTE instead) ==\n");
return;
}
/* Create a new clone family if needed */
if (whoToModify == THIS_ONLY) deriveObject(cwd);
thisPair = cellToPair(browserWindow, cell);
if (!thisPair) return;
LGetCell(charbuffer, &count, cell, iconList);
charbuffer[count] = 0;
name[0] = 0;
sscanf(charbuffer, "%s %s", qualifier, name);
if (strlen(name) && thisPair) {
renamePair(thisPair, allocStrCpy(name));
/* Possibly change the object's clone family */
confirmObjectType(cwd, whoToModify, RENAMING_SOMETHING);
updateBrowser(browserWindow);
}
else SysBeep(1);
}
/* Convert cells to one-dimensional indexes */
/* Indexing starts from number one */
int cellToIndex(iconList, cell)
ListHandle iconList;
Cell cell;
{
return (cell.v * ((*iconList)->dataBounds).right + cell.h + 1);
}
/* Given a cell, return the corresponding pair */
PAIR* cellToPair(browserWindow, cell)
WindowPtr browserWindow;
Cell cell;
{
ListHandle iconList = getBrowserIcons(browserWindow);
OBJECT* cwd = getBrowserTarget(browserWindow);
CONTEXT* context = getContext(cwd);
int index = cellToIndex(iconList, cell);
int viewMode = getViewMode(iconList);
return(indexedFind(context, index, viewMode));
}
/* Find the correct pair in the context, taking the mask into account */
PAIR* indexedFind(context, index, viewMode)
CONTEXT* context;
int index;
int viewMode;
{
switch (viewMode) {
case ALL:
return(findAllAsIndexed(context, index));
break;
case DATA:
return(findDataAsIndexed(context, index));
break;
case BEHAVIOR:
return(findOperAsIndexed(context, index));
break;
}
}
/* Get the next pair with the desired search mask */
PAIR* getNextMaskedPair(thisPair, viewMode)
PAIR* thisPair;
int viewMode;
{
while (thisPair) {
switch (viewMode) {
case ALL:
return(thisPair);
break;
case DATA:
if (thisPair->ofa) switch(recognizeObject(thisPair->ofa)) {
case REF:
case VAR:
case CONST:
return(thisPair);
}
break;
case BEHAVIOR:
if (thisPair->ofa) switch(recognizeObject(thisPair->ofa)) {
case PRIMITIVE:
case METHOD:
return(thisPair);
}
break;
}
thisPair = thisPair->sfa;
}
return(NIL);
}
/* Count the number of pairs, taking the mask into account */
int maskedCountPairs(context, viewMode)
CONTEXT* context;
int viewMode;
{
switch (viewMode) {
case ALL:
return(countAllPairs(context));
break;
case DATA:
return(countDataPairs(context));
break;
case BEHAVIOR:
return(countOperPairs(context));
break;
}
}
/* Check if an object is an array rather than conventional object */
/*
Return zero if the object is a normal object.
Return the count of anonymous data slots otherwise.
*/
int countArraySlots(ctxtObject)
OBJECT* ctxtObject;
{
CONTEXT* thisContext = getContext(ctxtObject);
PAIR* thisPair = thisContext->firstPair;
int array = TRUE;
while (thisPair) {
if (recognizeObject(thisPair->ofa) == VAR) {
array = FALSE;
break;
}
thisPair = thisPair->sfa;
}
if (array) return(ctxtObject->sfa - DATAOFFSET);
else return(0);
}
/*---------------------------------------------------------------------------*/
/* Auxiliary operations */
/* Build a textual description of an object */
/* The resulting format is:
'name (type)',
where name is either name or '<anon>', and
type is either "type:id#" or "id#".
The result will be stored in global variable 'charbuffer'.
*/
void decodeObjectType(thisName, object)
char* thisName;
OBJECT* object;
{
PAIR* typePair = findTypeForward(object);
if (thisName == NIL) thisName = "<anon>";
if (typePair)
sprintf(charbuffer, "%s (%s:%d)", thisName, typePair->nfa, object);
else sprintf(charbuffer, "%s (%d)", thisName, object);
CtoPstr(charbuffer);
}
/* Return an appropriate string */
char* asString(objectKind, hidden)
int objectKind;
int hidden;
{
char* string;
switch(objectKind) {
case PRIMITIVE: string = " P"; break;
case REF: string = " R"; break;
case VAR: string = " V"; break;
case CONST: string = " C"; break;
case METHOD: string = " M"; break;
}
/* 'Hidden' contains the encapsulation information. */
if (hidden) *string = '_';
else *string = '^';
return(string);
}
/*---------------------------------------------------------------------------*/
/* Icon list information field operations */
/* Create a list information structure */
/*
Each icon list must contain one of these structures stored
its 'RefCon' field.
*/
LINFO* createLinfo(viewMode, target, lastBrowser)
int viewMode; /* Icon list view mode (see 'portGlobal.h') */
OBJECT* target;
WindowPtr lastBrowser;
{
LINFO* newLinfo = (LINFO*)mycalloc(1, sizeof(LINFO));
newLinfo->lMode = viewMode;
newLinfo->target = target;
newLinfo->prevBrowser = lastBrowser;
return(newLinfo);
}
/* Delete a list information structure */
void deleteLinfo(thisLinfo)
LINFO* thisLinfo;
{
free(thisLinfo);
}
/* Return view mode info */
int getViewMode(iconList)
ListHandle iconList;
{
LINFO* thisLinfo = (LINFO*)(*iconList)->refCon;
if (thisLinfo) return(thisLinfo->lMode);
else return(ALL);
}
/* Set view mode info */
void setViewMode(iconList, viewMode)
ListHandle iconList;
int viewMode;
{
LINFO* thisLinfo = (LINFO*)(*iconList)->refCon;
if (thisLinfo) thisLinfo->lMode = viewMode;
}
/* Given a browser window, get the object being browsed */
OBJECT* getBrowserTarget(browserWindow)
WindowPtr browserWindow;
{
ListHandle iconList = getBrowserIcons(browserWindow);
LINFO* thisLinfo;
if (!iconList) return(NIL);
thisLinfo = (LINFO*)(*iconList)->refCon;
if (thisLinfo) return(thisLinfo->target);
else return(NIL);
}
/* Set the 'target' field of a browser window (stored in iconList's LINFO structure) */
void setBrowserTarget(browserWindow, target)
WindowPtr browserWindow;
OBJECT* target;
{
ListHandle iconList = getBrowserIcons(browserWindow);
LINFO* thisLinfo;
if (!iconList) return;
thisLinfo = (LINFO*)(*iconList)->refCon;
if (thisLinfo) thisLinfo->target = target;
}
/* Given a browser window, get the previous one */
WindowPtr getPrevBrowser(browserWindow)
WindowPtr browserWindow;
{
ListHandle iconList = getBrowserIcons(browserWindow);
LINFO* thisLinfo;
if (!iconList) return (NIL);
thisLinfo = (LINFO*)(*iconList)->refCon;
if (thisLinfo) return(thisLinfo->prevBrowser);
else return(NIL);
}
/* Set the 'prevBrowser' field of a browser window (stored in iconList's LINFO structure) */
void setPrevBrowser(browserWindow, previous)
WindowPtr browserWindow;
WindowPtr previous;
{
ListHandle iconList = getBrowserIcons(browserWindow);
LINFO* thisLinfo;
if (!iconList) return;
thisLinfo = (LINFO*)(*iconList)->refCon;
if (thisLinfo) thisLinfo->prevBrowser = previous;
}